package org.msn.server.handler.impl;

import io.netty.channel.ChannelHandlerContext;
import org.msn.config.CloseInfo;
import org.msn.config.MessageInfo;
import org.msn.config.RoomInfo;
import org.msn.dto.JoinRoomDTO;
import org.msn.dto.RoomInfoDTO;
import org.msn.model.pd.RestResultProto;
import org.msn.model.rest.RestCode;
import org.msn.mapper.database.Repository;
import org.msn.server.handler.RequestHandler;
import org.msn.util.JsonUtil;
import org.msn.util.RequestUtil;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

import static org.msn.util.RequestUtil.generateRestResultProto;

public class DefaultServerHandlerImpl extends RequestHandler {

    public DefaultServerHandlerImpl(Repository repository) {
        super(repository);
    }

    @Override
    protected void sendMsg(ChannelHandlerContext ctx, RestResultProto.RestResult data) {
        // 组内广播
//        MessageInfo messageInfo = MapUtil.createEntityFromMap((Map<String, Object>) data, MessageInfo.class);
        MessageInfo messageInfo = JsonUtil.formJson(data.getData(), MessageInfo.class);

        List<ChannelHandlerContext> channelHandlerContexts = repository.getAllRoomUser(messageInfo.getRoomName());

        for (ChannelHandlerContext key : channelHandlerContexts) {
            // 不广播自己
            if (key == ctx) {
                continue;
            }

            RestResultProto.RestResult result = generateRestResultProto(RestCode.sendMsg, data.getData());


            // 转发
            RequestUtil.sendRequest(key, result);
        }
    }

    @Override
    protected void getAllRoom(ChannelHandlerContext ctx, RestResultProto.RestResult data) {
        List<String> roomInfos = repository.getAllRoomName();

        // 存放所有的房间信息
        RestResultProto.RestResult result = generateRestResultProto(RestCode.getAllRoom, roomInfos);

        RequestUtil.sendRequest(ctx, result);
    }

    @Override
    protected void createRoom(ChannelHandlerContext ctx, RestResultProto.RestResult data) {
        RoomInfoDTO roomInfoDTO = JsonUtil.formJson(data.getData(), RoomInfoDTO.class);

        RoomInfo roomInfo = RoomInfo
                .builder()
                .name(roomInfoDTO.getName())
                .number(roomInfoDTO.getNumber())
                .map(new HashMap<>(roomInfoDTO.getNumber()))
                .build();

        repository.addRoomInfo(roomInfo);
        repository.addUserToRoom(ctx, roomInfoDTO.getUsername(), roomInfo.getName());
    }

    @Override
    protected void joinRoom(ChannelHandlerContext ctx, RestResultProto.RestResult data) {
        JoinRoomDTO joinRoomDTO = JsonUtil.formJson(data.getData(), JoinRoomDTO.class);

        RoomInfo roomInfo = repository.getRoomByName(joinRoomDTO.getRoomName());
        Integer userSize = repository.getRoomAllUserByName(joinRoomDTO.getRoomName());

        if (userSize == roomInfo.getNumber()) {
            // 当房间人数已经到达上限 返回加入失败 给客户端
            RestResultProto.RestResult result = generateRestResultProto(RestCode.failJoinRoom, null);
            RequestUtil.sendRequest(ctx, result);
            return;
        }

        repository.addUserToRoom(ctx, joinRoomDTO.getUsername(), roomInfo.getName());

        RestResultProto.RestResult result = generateRestResultProto(RestCode.successJoinRoom, null);

        RequestUtil.sendRequest(ctx, result);
    }

    @Override
    protected void leaveRoom(ChannelHandlerContext ctx, RestResultProto.RestResult data) {
        CloseInfo closeInfo = JsonUtil.formJson(data.getData(), CloseInfo.class);

        repository.removeUserFromRoom(closeInfo.getRoomName(), ctx);
        Integer userSize = repository.getRoomAllUserByName(closeInfo.getRoomName());
        if (userSize == 0) {
            repository.removeRoomByName(closeInfo.getRoomName());
        }
    }

    @Override
    protected void closeConnection(ChannelHandlerContext ctx, RestResultProto.RestResult data) {
        CloseInfo closeInfo = JsonUtil.formJson(data.getData(), CloseInfo.class);

        Integer userSize = repository.getRoomAllUserByName(closeInfo.getRoomName());
        if (userSize == 1) {
            repository.removeRoomByName(closeInfo.getRoomName());
        }
        repository.removeUserFromRoom(closeInfo.getRoomName(), ctx);
    }

    @Override
    protected void getRoomAllUserIP(ChannelHandlerContext ctx, RestResultProto.RestResult data) {
        RoomInfo roomInfo = JsonUtil.formJson(data.getData(), RoomInfo.class);

        List<String> list = new ArrayList<>();

        List<ChannelHandlerContext> channelHandlerContexts = repository.getRoomAllUserIPByName(roomInfo.getName());

        channelHandlerContexts.forEach(v -> {
            if (!v.equals(ctx)) {
                list.add(getRemoteIP(v));
            }
        });

        RestResultProto.RestResult result = generateRestResultProto(RestCode.getRoomAllUserIP, list);

        RequestUtil.sendRequest(ctx, result);
    }

    @Override
    protected void openVideo(ChannelHandlerContext ctx, RestResultProto.RestResult data) {
        RoomInfo roomInfo = JsonUtil.formJson(data.getData(), RoomInfo.class);

        List<ChannelHandlerContext> channelHandlerContexts = repository.getRoomAllUserIPByName(roomInfo.getName());

        channelHandlerContexts.stream().forEach(v -> {
            RestResultProto.RestResult result = generateRestResultProto(RestCode.openVideo, null);
            // 转发
            RequestUtil.sendRequest(v, result);
        });
    }

    @Override
    protected void openSound(ChannelHandlerContext ctx, RestResultProto.RestResult data) {
        RoomInfo roomInfo = JsonUtil.formJson(data.getData(), RoomInfo.class);

        List<ChannelHandlerContext> channelHandlerContexts = repository.getRoomAllUserIPByName(roomInfo.getName());

        channelHandlerContexts.stream().forEach(v -> {
            RestResultProto.RestResult result = generateRestResultProto(RestCode.openSound, null);
            // 转发
            RequestUtil.sendRequest(v, result);
        });
    }

    private String getRemoteIP(ChannelHandlerContext ctx) {
        return ctx.channel().remoteAddress().toString().substring(1);
    }
}
